#if 0
/*
    Copyright (C) 2021 Michel Stempin <michel.stempin@funkey-project.com>

    This file is part of the FunKey S GPIO keyboard daemon.

    This is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    The software is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, write to the Free
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.
*/

/**
 *  @file main.c
 *  This file contains the main function for the FunKey S GPIO daemon
 */
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <getopt.h>
#include "daemon.h"
#include "uinput.h"
#include "gpio_mapping.h"

#define VERSION "0.0.1"
#define PID_FILE "/var/run/fkgpiod.pid"

/* Background daemon flag */
static bool daemon = false;

/* GPIO configuration file name */
static const char *config_file = "fkgpiod.conf";

/* Print usage information */
static void print_usage(void)
{
    printf("Usage: fkgpiod [options] [config_file]\n"
           "Options:\n"
           " -d, -D, --daemonize                                Launch as a background daemon\n"
           " -h, -H, --help                                     Print option help\n"
           " -k, -K, --kill                                     Kill background daemon\n"
           " -v, --version                                      Print version information\n"
           "\n"
           "You can send script commands to the fkgpiod daemon by writting to the /tmp/fkgpiod.fifo file:\n"
           "\n"
           "$ echo \"LOAD /etc/fkgpiod.conf\" > /tmp/fkgpiod.fifo\n"
           "\n"
           "Available script commands (commands are not case sensitive):\n"
           "-----------------------------------------------------------\n"
           "CLEAR                                               Clear the button mapping\n"
           "DUMP                                                Dump the button mapping\n"
           "KEYDOWN <keycode>                                   Send a key down event with the given keycode\n"
           "KEYPRESS <keycode>                                  Send key press event with the given keycode\n"
           "KEYUP <keycode>                                     Send a key up event with the given keycode\n"
           "LOAD <configuration_file>                           Load a configuration file\n"
           "MAP <button_combination> TO KEY <keycode>           Map a button combination to a keycode\n"
           "MAP <button_combination> TO COMMAND <shell_command> Map a button combination to a Shell command\n"
           "SLEEP <delays_ms>                                   Sleep for the given delay in ms\n"
           "TYPE <string>                                       Type in a string\n"
           "UNMAP <button_combination>                          Unmap a button combination\n"
           "\n"
           "where:\n"
           " - <button_combination> is a list of UP, DOWN, LEFT, RIGHT, A, B, L, R, X, Y, MENU, START or FN\n"
           "   separated by \"+\" signs\n"
           " - <shell_command> is any valid Shell command with its arguments\n"
           " - <configuration_file> is the full path to a configurtion file\n"
           " - <delay_ms> is a delay in ms\n"
           " - <string> is a character string\n"
           " - <keycode> is taken from the Linux key and button codes\n"
           "     (https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h),\n"
           "     which in turn is modeled after USB HUT 1.12 (see http://www.usb.org/developers/hidpage):\n"
           "   - KEY_0 to KEY_9, KEY_A to KEY_Z\n"
           "   - KEY_F1 to KEY_F24, KEY_KP0 to KEY_KP9, KEY_PROG1 to KEY_PROG4\n"
           "   - BTN_0 to BTN_9, BTN_A to BTN_C, BTN_X to BTN_Z, BTN_BASE2 to BTN_BASE6\n"
           "   - BTN_BACK, BTN_BASE, BTN_DEAD, BTN_EXTRA, BTN_FORWARD, BTN_GAMEPAD, BTN_JOYSTICK, BTN_LEFT,\n"
           "     BTN_MIDDLE, BTN_MISC, BTN_MODE, BTN_MOUSE, BTN_PINKIE, BTN_RIGHT, BTN_SELECT, BTN_SIDE,\n"
           "     BTN_START, BTN_TASK, BTN_THUMB, BTN_THUMB2, BTN_THUMBL, BTN_THUMBR, BTN_TL, BTN_TL2, \n"
           "     BTN_TOP, BTN_TOP2, BTN_TR, BTN_TR2, BTN_TRIGGER,\n"
           "   - KEY_102ND, KEY_AGAIN, KEY_ALTERASE, KEY_APOSTROPHE, KEY_BACK, KEY_BACKSLASH, KEY_BACKSPACE,\n"
           "     KEY_BASSBOOST, KEY_BATTERY, KEY_BLUETOOTH, KEY_BOOKMARKS, KEY_BRIGHTNESSDOWN,\n"
           "     KEY_BRIGHTNESSUP, KEY_BRIGHTNESS_CYCLE, KEY_BRIGHTNESS_ZERO, KEY_CALC, KEY_CAMERA,\n"
           "     KEY_CANCEL, KEY_CAPSLOCK, KEY_CHAT, KEY_CLOSE, KEY_CLOSECD, KEY_COFFEE, KEY_COMMA,\n"
           "     KEY_COMPOSE, KEY_COMPUTER, KEY_CONFIG, KEY_CONNECT, KEY_COPY, KEY_CUT, KEY_CYCLEWINDOWS,\n"
           "     KEY_DASHBOARD, KEY_DELETE, KEY_DELETEFILE, KEY_DIRECTION, KEY_DISPLAY_OFF, KEY_DOCUMENTS,\n"
           "     KEY_DOT, KEY_DOWN, KEY_EDIT, KEY_EJECTCD, KEY_EJECTCLOSECD, KEY_EMAIL, KEY_END, KEY_ENTER,\n"
           "     KEY_EQUAL, KEY_ESC, KEY_EXIT, KEY_FASTFORWARD, KEY_FILE, KEY_FINANCE, KEY_FIND,\n"
           "     KEY_FORWARD, KEY_FORWARDMAIL, KEY_FRONT, KEY_GRAVE, KEY_HANGEUL, KEY_HANGUEL, KEY_HANJA,\n"
           "     KEY_HELP, KEY_HENKAN, KEY_HIRAGANA, KEY_HOME, KEY_HOMEPAGE, KEY_HP, KEY_INSERT, KEY_ISO,\n"
           "     KEY_KATAKANA, KEY_KATAKANAHIRAGANA, KEY_KBDILLUMDOWN, KEY_KBDILLUMTOGGLE, KEY_KBDILLUMUP,\n"
           "     KEY_KPASTERISK,KEY_KPCOMMA, KEY_KPDOT, KEY_KPENTER, KEY_KPEQUAL, KEY_KPJPCOMMA,\n"
           "     KEY_KPLEFTPAREN, KEY_KPMINUS, KEY_KPPLUS, KEY_KPPLUSMINUS, KEY_KPRIGHTPAREN, KEY_KPSLASH,\n"
           "     KEY_LEFT, KEY_LEFTALT, KEY_LEFTBRACE, KEY_LEFTCTRL, KEY_LEFTMETA, KEY_LEFTSHIFT,\n"
           "     KEY_LINEFEED, KEY_MACRO, KEY_MAIL, KEY_MEDIA, KEY_MENU, KEY_MICMUTE, KEY_MINUS, KEY_MOVE,\n"
           "     KEY_MSDOS, KEY_MUHENKAN, KEY_MUTE, KEY_NEW, KEY_NEXTSONG, KEY_NUMLOCK, KEY_OPEN,\n"
           "     KEY_PAGEDOWN, KEY_PAGEUP, KEY_PASTE, KEY_PAUSE, KEY_PAUSECD, KEY_PHONE, KEY_PLAY,\n"
           "     KEY_PLAYCD, KEY_PLAYPAUSE, KEY_POWER, EY_PREVIOUSSONG, KEY_PRINT, KEY_PROPS, KEY_QUESTION,\n"
           "     KEY_RECORD, KEY_REDO, KEY_REFRESH, KEY_REPLY, KEY_REWIND, KEY_RFKILL, KEY_RIGHT,\n"
           "     KEY_RIGHTALT, KEY_RIGHTBRACE, KEY_RIGHTCTRL, KEY_RIGHTMETA, KEY_RIGHTSHIFT, KEY_RO,\n"
           "     KEY_SAVE, KEY_SCALE, KEY_SCREENLOCK, KEY_SCROLLDOWN, KEY_SCROLLLOCK, KEY_SCROLLUP,\n"
           "     KEY_SEARCH, KEY_SEMICOLON, KEY_SEND, KEY_SENDFILE, KEY_SETUP, KEY_SHOP, KEY_SLASH,\n"
           "     KEY_SLEEP, KEY_SOUND, KEY_SPACE, KEY_SPORT, KEY_STOP, KEY_STOPCD, KEY_SUSPEND,\n"
           "     KEY_SWITCHVIDEOMODE, KEY_SYSRQ, KEY_TAB, KEY_UNDO, KEY_UNKNOWN, KEY_UP, KEY_UWB,\n"
           "     KEY_VIDEO_NEXT, KEY_VIDEO_PREV, KEY_VOLUMEDOWN, KEY_VOLUMEUP, KEY_WAKEUP, KEY_WIMAX,\n"
           "     KEY_WLAN, KEY_WWW, KEY_XFER, KEY_YEN, KEY_ZENKAKUHANKAKU\n");
}

/* Print version information */
static void print_version(void)
{
    printf("fkgpiod version " VERSION "\n");
    printf("FunKey S GPIO daemon\n\n");
    printf("Copyright (C) 2020-2021, Vincent Buso <vincent.buso@funkey-project.com>,\n");
    printf("Copyright (C) 2021, Michel Stempin  <michel.stempin@funkey-project.com>,\n");
    printf("All rights reserved.\n");
    printf("Released under the GNU Lesser General Public License version 2.1 or later\n");
}

/* Parse command line options */
static void parse_options(int argc, char *argv[])
{
    struct option long_options[] = {
        {"daemonize", 0, NULL, 0},
        {"help", 0, NULL, 0},
        {"kill", 0, NULL, 0},
        {"version", 0, NULL, 0},
        {0, 0, NULL, 0}};
    int c, opt;

    while (true)
    {
        c = getopt_long(argc, argv, "dDhHkKvV", long_options, &opt);
        if (c == -1)
        {

            /* End of options */
            break;
        }
        if (c == 0)
        {

            /* Match long option names and convert them to short options */
            if (!strcmp(long_options[opt].name, "daemonize"))
            {
                c = 'd';
            }
            else if (!strcmp(long_options[opt].name, "help"))
            {
                c = 'h';
            }
            else if (!strcmp(long_options[opt].name, "kill"))
            {
                c = 'k';
            }
            else if (!strcmp(long_options[opt].name, "version"))
            {
                c = 'v';
            }
        }
        switch (c)
        {
        case 'd':
        case 'D':

            /* Daemonize */
            daemon = true;
            break;

        case 'h':
        case 'H':

            /* Help */
            print_usage();
            exit(EXIT_SUCCESS);

        case 'k':
        case 'K':

            /* Kill running daemon */
            kill_daemon(PID_FILE);
            exit(EXIT_SUCCESS);

        case 'v':
        case 'V':

            /* Version */
            print_version();
            exit(EXIT_SUCCESS);

        default:
            print_usage();
            exit(EXIT_FAILURE);
        }
    }
    if (optind > argc)
    {
        print_usage();
        exit(EXIT_FAILURE);
    }
    else if (optind < argc)
    {

        /* Last argument is the GPIO confguration file name */
        config_file = strdup(argv[optind]);
    }
}

/* Entry point */
int main(int argc, char *argv[])
{
    mapping_list_t mapping_list;

    /* Parse command line options */
    // parse_options(argc, argv);
    if (daemon)
    {

        /* Run as a background daemon, redirect all output to syslog */
        //        to_log(&stdout);
        //        to_log(&stderr);
        daemonize("fkgpiod", "/", PID_FILE);
    }
    else
    {
        openlog("fkgpiod", LOG_PERROR | LOG_PID | LOG_NDELAY, LOG_DAEMON);
    }

    /* Initialize the uinput device */
    // init_uinput();
    init_gpio_mapping(config_file, &mapping_list);
    /* Initialize the GPIO mapping */
    // if (init_gpio_mapping(config_file, &mapping_list) == false) {

    //     /* Close the uinput device */
    //     close_uinput();
    // if (daemon) {

    //     /* Close the syslog */
    //     closelog();
    // }
    //     exit(EXIT_FAILURE);
    // }
    while (true)
    {

        /* Main loop to handle the GPIOs */
        handle_gpio_mapping(&mapping_list);
    }

    /* Deinitialize the GPIO mapping */
    deinit_gpio_mapping();

    /* Close the uinput device */
    close_uinput();
    if (daemon)
    {

        /* Close the syslog */
        closelog();
    }
    return EXIT_SUCCESS;
}

int main()
{
    FILE *file;
    char line[100];

    // 打开配置文件
    file = fopen("fkgpiod.conf", "r");
    if (file == NULL)
    {
        printf("could not open file\n");
        return 1;
    }

    // 逐行读取并输出内容
    while (fgets(line, sizeof(line), file))
    {
        printf("%s", line);
    }

    while (1)
    {
    }

    // 关闭文件
    fclose(file);

    return 0;
}

#endif

// #include <stdio.h>
// #include <stdlib.h>
// #include <fcntl.h>
// #include <linux/input.h>

// #define KEYBOARD_EVENT "/dev/input/event3"

// int main() {
//     int fd;
//     struct input_event ev;

//     fd = open(KEYBOARD_EVENT, O_RDONLY);
//     if (fd == -1) {
//         perror("open");
//         exit(EXIT_FAILURE);
//     }

//     while (1) {
//         if (read(fd, &ev, sizeof(struct input_event)) == -1) {
//             perror("read");
//             exit(EXIT_FAILURE);
//         }

//         if (ev.type == EV_KEY && (ev.code == KEY_A && ev.code == KEY_B)) {
//             printf("H\n");
//         }
//     }

//     close(fd);
//     return 0;
// }

#if 0
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <linux/input.h>

#define KEYBOARD_EVENT "/dev/input/event3"
#define KEY_A 30
#define KEY_B 48
int a_pressed = 0;
int b_pressed = 0;
struct input_event ev;

void key_combination_press(void)
{
    if (ev.type == EV_KEY)
    {
        if (ev.code == KEY_A)
        {
            if (ev.value == 1)
            {
                a_pressed = 1;
            }
            else if (ev.value == 0)
            {
                a_pressed = 0;
            }
        }
        else if (ev.code == KEY_B)
        {
            if (ev.value == 1)
            {
                b_pressed = 1;
            }
            else if (ev.value == 0)
            {
                b_pressed = 0;
            }
        }

        if (a_pressed && b_pressed)
        {
            printf("H\n");
        }
    }
}

int main()
{
    int fd;

    fd = open(KEYBOARD_EVENT, O_RDONLY);
    if (fd == -1)
    {
        perror("open");
        exit(EXIT_FAILURE);
    }

    while (1)
    {
        if (read(fd, &ev, sizeof(struct input_event)) == -1)
        {
            perror("read");
            exit(EXIT_FAILURE);
        }
        key_combination_press();
    }

    close(fd);
    return 0;
}
#endif

#if 0 /* 实现报值 */
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <linux/input.h>
#include "keydefs.h"
#include <stdlib.h>
#define KEYBOARD_EVENT "/dev/input/event3"

#define MAPPING_TYPES     \
    X(MAPPING_KEY, "KEY") \
    X(MAPPING_COMMAND, "COMMAND")
#undef X
#define X(a, b) a,

typedef enum
{
    MAPPING_TYPES
} mapping_type_t;

struct two_key_combination
{
    int key1_code;
    int key2_code;
    mapping_type_t type;
    union
    {
        char *command;
        int keycode;
    } value;
    int key1_value;
    int key2_value;
};

void key_combination_press(struct input_event ev, struct two_key_combination *state)
{

    if (ev.type == EV_KEY)
    {
        if (ev.code == state->key1_code)
        {
            state->key1_value = ev.value;
        }
        else if (ev.code == state->key2_code)
        {
            state->key2_value = ev.value;
        }
        if (state->key1_value && state->key2_value)
        {
            if (state->type == MAPPING_KEY)
            {
                printf("[%s][%d]\n", key_names[state->value.keycode], state->value.keycode);
            }
            else if (state->type == MAPPING_COMMAND)
            {
                printf("command[%s]\n", state->value.command);
                system(state->value.command);
            }
        }
    }
}

#define KEY_SUM 3
int main()
{
    int fd;
    struct input_event ev;
    // struct two_key_combination state = {KEY_A, KEY_B, MAPPING_KEY, KEY_H};
    struct two_key_combination state[KEY_SUM] = {{KEY_A, KEY_B, MAPPING_COMMAND, "ls"}, {KEY_A, KEY_C, MAPPING_COMMAND, "pwd"}, {KEY_A, KEY_D, MAPPING_COMMAND, "ls -a"}};
    fd = open(KEYBOARD_EVENT, O_RDONLY);
    if (fd == -1)
    {
        perror("open");
        exit(EXIT_FAILURE);
    }

    while (1)
    {
        if (read(fd, &ev, sizeof(struct input_event)) == -1)
        {
            perror("read");
            exit(EXIT_FAILURE);
        }
        for (int i = 0; i < KEY_SUM; i++)
        {
            key_combination_press(ev, &state[i]);
        }
        // key_combination_press(ev, &state[0]);
        // key_combination_press(ev, &state[1]);
    }
    close(fd);
    return EXIT_SUCCESS;
}
#endif

#if 0
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <linux/input.h>
#include "keydefs.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <linux/input.h>
#define KEYBOARD_EVENT "/dev/input/event3"

#define MAPPING_TYPES     \
    X(MAPPING_KEY, "KEY") \
    X(MAPPING_COMMAND, "COMMAND")
#undef X
#define X(a, b) a,
#define MAX_BUFFER_LENGTH 256
#define MAX_LINE_LENGTH 256
/* Line buffer for parsing */
static char line[MAX_LINE_LENGTH + 1];
typedef enum
{
    MAPPING_TYPES
} mapping_type_t;

struct two_key_combination
{
    int key1_code;
    int key2_code;
    mapping_type_t type;
    union
    {
        char *command;
        int keycode;
    } value;
    int key1_value;
    int key2_value;
};

void key_combination_press(struct input_event ev, struct two_key_combination *state)
{

    if (ev.type == EV_KEY)
    {
        if (ev.code == state->key1_code)
        {
            state->key1_value = ev.value;
        }
        else if (ev.code == state->key2_code)
        {
            state->key2_value = ev.value;
        }
        if (state->key1_value && state->key2_value)
        {
            if (state->type == MAPPING_KEY)
            {
                printf("[%s][%d]\n", key_names[state->value.keycode], state->value.keycode);
            }
            else if (state->type == MAPPING_COMMAND)
            {
                printf("command[%s]\n", state->value.command);
                system(state->value.command);
            }
        }
    }
}

static int lookup_key(char *token)
{
    int key;

    for (key = 0; key_names[key].code >= 0; key++)
    {
        if (strcasecmp(token, key_names[key].name) == 0)
        {
            // printf("Found keycode \"%s\" (%d)\n", key_names[key].name,
            //        key_names[key].code);
            return key;
        }
    }
    //  printf("Unknown key \"%s\"\n", token);
    return -1;
}

void parse_config_lines(char *line, struct two_key_combination *state)
{
    char buf1[100], buf2[100], buf3[100], buf4[100]; // 假设每个buf足够大
    char *token;
    token = strtok(line, " ");
    if (token != NULL)
    {
        strncpy(buf1, token, sizeof(buf1));
        if (lookup_key(&buf1) != -1)
        {
            state->key1_code = lookup_key(&buf1);
            printf("key1_code=[%d]\n", state->key1_code);
        }

        // printf("%s\n", buf1); // 可以根据需要进行其他操作
        //  printf("[%d]\n", lookup_key(&buf1));
    }

    token = strtok(NULL, " ");
    if (token != NULL)
    {
        strncpy(buf2, token, sizeof(buf2));
        if (lookup_key(&buf2) != -1)
        {
            state->key2_code = lookup_key(&buf2);
            printf("key2_code=[%s][%d]\n", buf2,state->key2_code);
        }
        // printf("%s\n", buf2); // 可以根据需要进行其他操作
        // printf("[%d]\n", lookup_key(&buf2));
    }

    token = strtok(NULL, " ");
    if (token != NULL)
    {
        strncpy(buf3, token, sizeof(buf3));
        printf("%s\n", buf3); // 可以根据需要进行其他操作
        if (strcmp(buf3, "COMMAND") == 0)
        {
            state->type = MAPPING_COMMAND;

            // printf("COMMAND\n");
        }
        else if (strcmp(buf3, "KEY") == 0)
        {
            state->type = MAPPING_KEY;
        }
        printf("type=[%d]\n", state->type);
    }

    token = strtok(NULL, " ");
    if (token != NULL)
    {
        strncpy(buf4, token, sizeof(buf4));
        if (state->type = MAPPING_COMMAND)
        {
            state->value.command = buf4;
            printf("command=[%s]\n", state->value.command);
        }
        else if (state->type = MAPPING_KEY)
        {
            if (lookup_key(&buf4) != -1)
            {
                state->value.keycode = lookup_key(&buf4);
                 printf("keycode=[%s]\n", state->value.keycode);
            }
        }

        // printf("%s\n", buf4); // 可以根据需要进行其他操作
        //  system(buf4);
    }
}

void parse_config_files(const char *name)
{
    FILE *fp;
    int line_number = 0;
    printf("LOAD file %s\n", name);
    if ((fp = fopen(name, "r")) == NULL)
    {
        printf("Cannot open file \"%s\"\n", name);
        return;
    }
    while (!feof(fp))
    {
        if (fgets(line, MAX_LINE_LENGTH, fp) != line)
        {
            if (!feof(fp))
            {
                printf("Error reading file \"%s\": %s\n", name,
                       strerror(errno));
                fclose(fp);
                return;
            }
        }
        line_number++;
        if (line[0] == '#')
        {

            /* Skip comment lines */
            continue;
        }

        /* Remove trailing CR/LF */
        strtok(line, "\r\n");

        /* Parse a configuration line */
        printf("%s\n", line);
    }
}

int main()
{
    struct two_key_combination state;
    char line[] = "KEY_A KEY_C COMMAND pwd";
    int fd;
    struct input_event ev;
    fd = open(KEYBOARD_EVENT, O_RDONLY);
    if (fd == -1)
    {
        perror("open");
        exit(EXIT_FAILURE);
    }
    parse_config_lines(line, &state);
    while (1)
    {
        if (read(fd, &ev, sizeof(struct input_event)) == -1)
        {
            perror("read");
            exit(EXIT_FAILURE);
        }
        key_combination_press(ev, &state);
    }

    // parse_config_lines(&line);

    // parse_config_files("fkgpiod.conf");
    return 0;
}
#endif
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <linux/input.h>
#include "keydefs.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "uinput.h"
#include <linux/uinput.h>
#include <unistd.h>
#include <signal.h>
#define KEYBOARD_EVENT "/dev/input/event1"

#define MAPPING_TYPES     \
    X(MAPPING_KEY, "KEY") \
    X(MAPPING_COMMAND, "COMMAND")
#undef X
#define X(a, b) a,

typedef enum
{
    MAPPING_TYPES
} mapping_type_t;

struct two_key_combination
{
    int key1_code;
    int key2_code;
    mapping_type_t type;
    union
    {
        char *command[100];
        int keycode;
    } value;
    int key1_value;
    int key2_value;
};

#define MAX_BUFFER_LENGTH 256
#define MAX_LINE_LENGTH 256
#define KEY_SUM 24
/* Line buffer for parsing */
static char line[MAX_LINE_LENGTH + 1];
int line_number = 0;
struct two_key_combination state[24];

static int lookup_key(char *token)
{
    int key;

    for (key = 0; key_names[key].code >= 0; key++)
    {
        if (strcasecmp(token, key_names[key].name) == 0)
        {
            // printf("Found keycode \"%s\" (%d)\n", key_names[key].name,
            //        key_names[key].code);
            return key;
        }
    }
    //  printf("Unknown key \"%s\"\n", token);
    return -1;
}

void key_combination_press(struct input_event ev, struct two_key_combination *state)
{

    if (ev.type == EV_KEY)
    {
        if (ev.code == state->key1_code)
        {
            state->key1_value = ev.value;
        }
        else if (ev.code == state->key2_code)
        {
            state->key2_value = ev.value;
        }
        if (state->key1_value && state->key2_value)
        {
            if (state->type == MAPPING_KEY)
            {
                printf("[%s][%d]\n", key_names[state->value.keycode], state->value.keycode);

                sendKey(state->value.keycode, 1);
                usleep(2 * 1000);
                sendKey(state->value.keycode, 0);
            }
            else if (state->type == MAPPING_COMMAND)
            {
                printf("command[%s]\n", state->value.command);
                system(state->value.command);
            }
        }
    }
}

void parse_config_lines(char *line, struct two_key_combination *state)
{
    char buf1[100], buf2[100], buf3[100], buf4[100]; // 假设每个buf足够大
    char *token;
    token = strtok(line, " ");
    if (token != NULL)
    {
        strncpy(buf1, token, sizeof(buf1));
        if (lookup_key(&buf1) != -1)
        {
            state->key1_code = lookup_key(&buf1);
            printf("k1code=[%s][%d] ", buf1, state->key1_code);
        }

        // printf("%s\n", buf1); // 可以根据需要进行其他操作
        //  printf("[%d]\n", lookup_key(&buf1));
    }

    token = strtok(NULL, " ");
    if (token != NULL)
    {
        strncpy(buf2, token, sizeof(buf2));
        if (lookup_key(&buf2) != -1)
        {
            state->key2_code = lookup_key(&buf2);
            printf("k2code=[%s][%d] ", buf2, state->key2_code);
        }
        // printf("%s\n", buf2); // 可以根据需要进行其他操作
        // printf("[%d]\n", lookup_key(&buf2));
    }

    token = strtok(NULL, " ");
    if (token != NULL)
    {
        strncpy(buf3, token, sizeof(buf3));
        if (strcmp(buf3, "COMMAND") == 0)
        {
            state->type = MAPPING_COMMAND;
        }
        else if (strcmp(buf3, "KEY") == 0)
        {
            state->type = MAPPING_KEY;
        }
        printf("type=[%d] ", state->type);
    }

    token = strtok(NULL, "");
    if (token != NULL)
    {
        printf("token4 = %s ", token);
        strncpy(buf4, token, sizeof(buf4));
        if (state->type == MAPPING_COMMAND)
        {

            strcpy((char *)state->value.command, (const char *)buf4);
            printf("command=[%s]\n", state->value.command);
        }
        else if (state->type == MAPPING_KEY)
        {
            if (lookup_key(&buf4) != -1)
            {
                state->value.keycode = lookup_key(&buf4);
                printf("new_code=[%s][%d]\n", buf4, state->value.keycode);
            }
        }

        // printf("%s\n", buf4); // 可以根据需要进行其他操作
        //  system(buf4);
    }
}

int parse_config_files(const char *name)
{
    FILE *fp;

    printf("LOAD file %s\n", name);
    if ((fp = fopen(name, "r")) == NULL)
    {
        printf("Cannot open file \"%s\"\n", name);
        return EXIT_FAILURE;
    }
    while (!feof(fp))
    {
        if (fgets(line, MAX_LINE_LENGTH, fp) != line)
        {
            if (!feof(fp))
            {
                printf("Error reading file \"%s\": %s\n", name,
                       strerror(errno));
                fclose(fp);
                return;
            }
        }

        if (line[0] == '#')
        {

            /* Skip comment lines */
            continue;
        }

        /* Remove trailing CR/LF */
        strtok(line, "\r\n");

        /* Parse a configuration line */
        // printf("%s\n", line);
        parse_config_lines(line, &state[line_number]);
        line_number++;
    }
    printf("line_number = %d\n", line_number);
    return EXIT_SUCCESS;
}

void print_value(struct two_key_combination combination)
{
    printf("key1_code: %d\n", combination.key1_code);
    printf("key2_code: %d\n", combination.key2_code);
    printf("type: %d\n", combination.type);
    if (combination.type == MAPPING_COMMAND)
    {
        printf("command: %s\n", combination.value.command);
    }
    else if (combination.type == MAPPING_KEY)
    {
        printf("keycode: %d\n", combination.value.keycode);
    }
    printf("key1_value: %d\n", combination.key1_value);
    printf("key2_value: %d\n", combination.key2_value);
}

int main(int argc, char *argv[])
{
    int fd;
    struct input_event ev;

    if (init_uinput() == EXIT_FAILURE)
    {
        printf("init uinput fail\n");
        return EXIT_FAILURE;
    }

    fd = open(KEYBOARD_EVENT, O_RDONLY);
    if (fd == NULL)
    {
        printf("could not open file\n");
        return EXIT_FAILURE;
    }

    if (argc > 1)
    {
        if (parse_config_files(strdup(argv[optind])) == EXIT_FAILURE)
        {
            return EXIT_FAILURE;
        }
    }
    else if (parse_config_files("/etc/fkgpiod.conf") == EXIT_FAILURE)
    {
        // perror("can't open fkgpiod.conf");
        return EXIT_FAILURE;
    }

    while (1)
    {
        if (read(fd, &ev, sizeof(struct input_event)) == -1)
        {
            perror("read");
            return EXIT_FAILURE;
        }
        for (int i = 0; i < line_number; i++)
        {
            key_combination_press(ev, &state[i]);
        }
    }
    close(fd);
    return EXIT_SUCCESS;
}
